package com.frank.loadinglibrary.special.element;

import com.frank.loadinglibrary.ResourceTable;
import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.*;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.agp.utils.TextAlignment;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.Resource;
import ohos.global.resource.WrongTypeException;
import ohos.hiviewdfx.HiLog;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class TitanicLoadingElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorGroup> {

    private PixelMap wave;
    private Paint textPaint;
    private Color textColor = new Color(Color.getIntColor("#212121"));
    private float maskX;
    private float maskY;
    private int reverse = 1;
    float height;
    private PixelMapHolder mShapePixMapHold;
    private Font textFont;
    private String drawText;

    public TitanicLoadingElement(IComponentCallback componentCallback) {
        callback = componentCallback;
        initFont(componentCallback.getContext());
    }

    @Override
    public void initPaint() {
        super.initPaint();
        textPaint = new Paint();
        if (callback != null) {
            String path = callback.getContext().getCacheDir() + "/test.ttf";
            File file = new File(path);
            textFont = new Font.Builder(file).build();
        }

        try {
            if (callback != null) {
                drawText = callback.getContext().getResourceManager().getElement(ResourceTable.String_loading).getString();
            }
        } catch (IOException | NotExistException | WrongTypeException e) {
            e.printStackTrace();
        } finally {
            if (drawText == null || "".equals(drawText)) {
                drawText = "Loading";
            }
        }
        textPaint.setStyle(Paint.Style.FILL_STYLE);
        textPaint.setStrokeWidth(8);
        textPaint.setTextSize(100);
        textPaint.setTextAlign(TextAlignment.CENTER);
        textPaint.setColor(textColor);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        height = getHeight();
        RectFloat rectF = new RectFloat(0, 0, getWidth(), getHeight());
        //计算baseline
        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
        float distance = (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
        float baseline = rectF.getCenter().getPointY() + distance;
        if (mShapePixMapHold == null) {
            try {
                createPixMapShader();
            } catch (IOException | NotExistException e) {
                e.printStackTrace();
            }
        }

        int mLayerId = canvas.saveLayer(new RectFloat(0, 0, getWidth(), getHeight()), textPaint);
        textPaint.setFont(textFont);
        canvas.drawText(textPaint, drawText, rectF.getCenter().getPointX(), baseline);
        textPaint.setBlendMode(BlendMode.SRC_IN);
        canvas.drawPixelMapHolder(mShapePixMapHold, maskX, maskY, textPaint);
        textPaint.setBlendMode(null);
        canvas.restoreToCount(mLayerId);
    }

    @Override
    public ArrayList<AnimatorGroup> onCreateAnimators() {
        AnimatorValue maskXAnimator = new AnimatorValue();
        maskXAnimator.setDuration(1000);
        maskXAnimator.setLoopedCount(Animator.INFINITE);
        maskXAnimator.setValueUpdateListener((animatorValue, v) -> {
            maskX = 200 * v;

            if (callback != null) {
                callback.reflushComponent();
            }
        });

        AnimatorValue maskYAnimator = new AnimatorValue();
        maskYAnimator.setDuration(10000);
        maskYAnimator.setLoopedCount(Animator.INFINITE);
        maskYAnimator.setValueUpdateListener((animatorValue, v) -> {
            maskY = (70f) * (0.5f - v) / 0.5f * reverse;
            if (callback != null) {
                callback.reflushComponent();
            }
        });
        maskYAnimator.setLoopedListener(animator -> reverse *= -1);

        AnimatorGroup animatorGroup = new AnimatorGroup();
        animatorGroup.setLoopedCount(-1);
        AnimatorGroup.Builder animatorGroupBuilder = animatorGroup.build();
        animatorGroupBuilder.addAnimators(maskXAnimator, maskYAnimator);

        ArrayList<AnimatorGroup> list = new ArrayList<>();
        list.add(animatorGroup);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public BaseAnimationController.IAnimationController initAnimationController() {
        return this;
    }

    private void createPixMapShader() throws IOException, NotExistException {
        if (callback != null) {
            Resource media = callback.getContext().getResourceManager().getResource(ResourceTable.Media_wave);
            ImageSource.SourceOptions sOptions = new ImageSource.SourceOptions();
            ImageSource imageSource = ImageSource.create(media, sOptions);
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            wave = imageSource.createPixelmap(decodingOptions);

            int waveW = wave.getImageInfo().size.width;
            int waveH = wave.getImageInfo().size.height;
            PixelMap.InitializationOptions options = new PixelMap.InitializationOptions();
            options.pixelFormat = PixelFormat.ARGB_8888;
            options.size = new Size((int) getWidth(), waveH);
            options.editable = true;
            PixelMap defaultPixmap = PixelMap.create(options);

            //根据图片生成Texture(由像素组成的像素映射文件)
            Texture tt = new Texture(defaultPixmap);
            //将指定图像绘制到canva
            PixelMapHolder pixelMapHolder = new PixelMapHolder(wave);
            //设置颜色的亮度
            ColorMatrix lumMatrix = new ColorMatrix();
            lumMatrix.setSaturation(3);
            Paint paint = new Paint();
            Canvas canvas = new Canvas(tt);
            canvas.drawColor(textColor.getValue(), BlendMode.SRC);
            float count = (getWidth() + waveW - 1) / waveW;

            for (int idx = 0; idx < count; ++idx) {
                canvas.drawPixelMapHolder(pixelMapHolder, (float) idx * waveW, 0, paint);
            }
            mShapePixMapHold = new PixelMapHolder(defaultPixmap);
        }
    }

    @Override
    public void release() {
        super.release();
        if (wave != null) {
            wave.release();
            wave = null;
        }
    }

    private void initFont(Context ctx) {
        Resource FI = null;
        FileOutputStream fos = null;
        String path = ctx.getCacheDir() + "/test.ttf";
        File ttfFile = new File(path);
        if (!ttfFile.exists()) {
            try {
                FI = ctx.getResourceManager().getRawFileEntry("resources/rawfile/Satisfy-Regular.ttf").openRawFile();
                fos = new FileOutputStream(path);

                byte[] buffer = new byte[4096];
                int count = 0;
                while ((count = FI.read(buffer)) != -1) {
                    fos.write(buffer, 0, count);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (FI != null) {
                    try {
                        FI.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }
}
